//! 该库是对[tracing](https://docs.rs/tracing/latest/tracing/)库的增强
//!
//! 在项目的的根目录创建一个文件名为`tracing-log.toml`或`tracing-log.yaml`或`tracing-log.yml`的文件，
//! 也可通过环境变量`TRACING_LOG_FILE`来指定配置文件
//! 
//! 该库会根据配置文件动态的注册日志，然后调用`init_tracing_log`方法即可完成日志的初始化工作
//!
//! > 优先级
//! > TRACING_LOG_FILE > toml > yaml > yml
//! # 示例
//!
//! ```toml
//! # 文件名 tracing-log.toml
//!
//! # 最小日志级别，低于此日志级别则不打印，非必填(可选值：`error`、`warn`、`info`、`debug`、`trace`)
//! min-level = "info"
//! # 控制台输出配置
//! [console]
//! # 日志级别, 必填(可选值：`error`、`warn`、`info`、`debug`、`trace`)
//! level = "info"
//! # 是否打印线程名 默认为 true
//! thread = true
//! # 时间格式 默认为 "%Y-%m-%d %H:%M:%S"
//! format = "%Y-%m-%d %H:%M:%S"
//! # 是否打印行号  默认为 false
//! line-number = true
//!
//! # 文件输出配置
//! [[file]]
//! # 日志级别, 必填(可选值：`error`、`warn`、`info`、`debug`、`trace`)
//! level = "info"
//! # 是否打印线程名 默认为 true
//! thread = true
//! # 时间格式 默认为 "%Y-%m-%d %H:%M:%S"
//! format = "%Y-%m-%d %H:%M:%S"
//! # 是否打印行号 默认为 false
//! line-number = true
//! # 保留的最大文件数量 默认为 30
//! max-files = 60
//! # 日志文件滚动的固定时间段，可选值: "minutely"、"hourly"、"daily"、"never", 默认值为: "daily"
//! rotation = "daily"
//! # 生成的文件名前缀, 必填
//! prefix = "info"
//! # 生成的文件名后缀, 默认值为: "log"
//! suffix = "log"
//! # 生成的文件所在目录前缀, 默认值为: "logs"
//! directory = "logs"
//! # 只记录`target`指定的值的日志 (不配置，则记录全部)
//! target = "abc"
//!
//! [[file]]
//! level = "error"
//! thread = false
//! format = "%Y-%m-%d %H:%M:%S"
//! line-number = true
//! max-files = 60
//! rotation = "daily"
//! prefix = "error"
//! directory = "logs"
//!
//! [[file]]
//! level = "error"
//! thread = false
//! format = "%Y-%m-%d %H:%M:%S"
//! line-number = true
//! max-files = 60
//! rotation = "daily"
//! prefix = "error-worker"
//! directory = "logs"
//! target = "worker"
//! ```
#[cfg(feature = "blocking")]
mod blocking_layer;
mod config;
#[cfg(not(feature = "blocking"))]
mod non_blocking_layer;

use tracing::level_filters::LevelFilter;
use tracing_appender::rolling::Rotation;
#[cfg(feature = "blocking")]
use crate::blocking_layer::{get_console_layer, get_file_layer};
use crate::config::TracingLog;

#[cfg(not(feature = "blocking"))]
use crate::non_blocking_layer::{get_console_layer, get_file_layer};
use tracing_subscriber::Registry;
use tracing_subscriber::layer::SubscriberExt;
use tracing_subscriber::util::SubscriberInitExt;

pub fn init_tracing_log() {
    let config = TracingLog::config();
    let option = &config.min_level;

    let console = &config.console;
    let files = &config.file;

    let console = get_console_layer(console);

    let file_layers = files
        .iter()
        .map(|file| get_file_layer(file))
        .collect::<Vec<_>>();

    let layered = Registry::default().with(console).with(file_layers);

    if let Some(level)  = option {
        let min_level = level_from_str(level);
        layered.with(min_level).init();
    } else {
        layered.init();
    }

    #[cfg(feature = "blocking")]
    tracing::debug!("blocking log enabled");

    #[cfg(not(feature = "blocking"))]
    tracing::debug!("non blocking log enabled");
}



fn level_from_str(level: &str) -> LevelFilter {
    match level {
        s if s.eq_ignore_ascii_case("error") => LevelFilter::ERROR,
        s if s.eq_ignore_ascii_case("warn") => LevelFilter::WARN,
        s if s.eq_ignore_ascii_case("info") => LevelFilter::INFO,
        s if s.eq_ignore_ascii_case("debug") => LevelFilter::DEBUG,
        s if s.eq_ignore_ascii_case("trace") => LevelFilter::TRACE,
        _ => panic!("未知的`level`属性值, 可选值：`error`、`warn`、`info`、`debug`、`trace`"),
    }
}

fn rotation_from_str(rotation: &str) -> Rotation {
    match rotation {
        s if s.eq_ignore_ascii_case("minutely") => Rotation::MINUTELY,
        s if s.eq_ignore_ascii_case("hourly") => Rotation::HOURLY,
        s if s.eq_ignore_ascii_case("daily") => Rotation::DAILY,
        s if s.eq_ignore_ascii_case("never") => Rotation::NEVER,
        _ => panic!("未知的`rotation`属性值, 可选值：`minutely`、`hourly`、`daily`、`never`"),
    }
}